﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ComLib
{
    #region 层级数据转换

    public class CustomHierarchicalDataSource : IHierarchicalDataSource
    {
        private CustomHierarchicalDataSourceView _view = null;

        public HierarchicalDataSourceView GetHierarchicalView(string viewPath)
        {
            if (null == this._view)
                this._view = new CustomHierarchicalDataSourceView(this, viewPath);

            return this._view;
        }

        public event EventHandler DataSourceChanged;

        public string DataParentIdField { get; set; }

        public string DataIdField { get; set; }

        public object CustomDataSurce { get; set; }

        public CustomHierarchicalDataSource(object customDataSource)
        {
            if (customDataSource is DataTable)
            {
                this.CustomDataSurce = customDataSource;
            }
            else if (customDataSource is IList)
            {
                this.CustomDataSurce = DataTableExtensions.nullListToDataTable((IList) customDataSource);
            }
            else if (customDataSource == null)
            {
                this.CustomDataSurce = new DataTable();
            }
            else
            {
                throw new NotSupportedException("数据源只支持DataTable和IList！");
            }
        }

        public CustomHierarchicalDataSource(object customDataSource,string dataIdField,string dataParentIdField)
        {
            if (customDataSource is DataTable)
            {
                this.CustomDataSurce = customDataSource;
            }
            else if (customDataSource is IList)
            {
                this.CustomDataSurce = DataTableExtensions.nullListToDataTable((IList)customDataSource);
            }
            else if (customDataSource == null)
            {
                this.CustomDataSurce = new DataTable();
            }
            else
            {
                throw new NotSupportedException("数据源只支持DataTable和IList！");
            }

            this.DataIdField = dataIdField;
            this.DataParentIdField = dataParentIdField;
        }
    }

    public class CustomHierarchicalDataSourceView : HierarchicalDataSourceView
    {
        private string _viewPath;
        private readonly CustomHierarchicalDataSource _owner;


        public CustomHierarchicalDataSourceView(CustomHierarchicalDataSource owner, string viewPath)
        {
            this._viewPath = viewPath;
            this._owner = owner;
        }


        public override IHierarchicalEnumerable Select()
        {
            DataTable dt = (DataTable)this._owner.CustomDataSurce;

            CustomHierarchicalEnumerable data = new CustomHierarchicalEnumerable();

            bool hasParent = false;

            foreach (DataRow crow in dt.Rows)
            {
                object[] array1 = crow.ItemArray;
                hasParent = false;

                foreach (DataRow prow in dt.Rows)
                {
                    object[] array2 = prow.ItemArray;
                    //子节点
                    string a = crow[_owner.DataParentIdField].ToString();
                    //根节点
                    string b = prow[_owner.DataIdField].ToString();
                    if (a == b)
                    {
                        hasParent = true;
                        break;
                    }
                }
                //添加根节点
                if (!hasParent)
                    data.Add(new CustomHierarchyData(_owner.DataParentIdField, _owner.DataIdField, crow));
            }

            return data;
        }
    }

    public class CustomHierarchicalEnumerable : ArrayList, IHierarchicalEnumerable
    {
        public IHierarchyData GetHierarchyData(object enumeratedItem)
        {
            return (CustomHierarchyData)enumeratedItem;
        }
    }

    public class CustomHierarchyData : IHierarchyData, ICustomTypeDescriptor
    {
        private readonly DataRow _item;
        private readonly string _dataParentIdField;
        private readonly string _dataIdField;

        public CustomHierarchyData(string dataParentIdField, string dataIdField, DataRow item)
        {
            this._item = item;
            this._dataParentIdField = dataParentIdField;
            this._dataIdField = dataIdField;
        }

        bool IHierarchyData.HasChildren
        {
            get
            {
                foreach (DataRow row in _item.Table.Rows)
                {
                    object[] array1 = row.ItemArray;
                    object[] array2 = _item.ItemArray;
                    string a = row[_dataParentIdField].ToString();
                    string b = _item[_dataIdField].ToString();
                    //HttpContext.Current.Response.Write(array1[2] + "-" + a + "--" + array2[2] + "-" + b + "<br>");
                    if (a == b)
                        return true;
                }

                return false;
            }
        }

        object IHierarchyData.Item
        {
            get
            {
                return _item;
            }
        }

        public override string ToString()
        {
            return _dataIdField;
        }

        string IHierarchyData.Path
        {
            get
            {
                string path = "/*[position()=1]";

                GetPath(_item, ref path);
                return path;
            }
        }

        void GetPath(DataRow crow, ref string path)
        {

            foreach (DataRow row in _item.Table.Rows)
            {
                string c, d;
                c = crow.ItemArray[2].ToString();
                d = crow.ItemArray[0].ToString();
                string a = crow[_dataParentIdField].ToString();
                string b = row[_dataIdField].ToString();
                if (a == b)
                {
                    path = "/*[position()=1]" + path;

                    //GetPath(row, ref path);
                    //HttpContext.Current.Response.Write("begin<br>" + c + "--" + a + "--" + b + "<br>end<br>");
                    //HttpContext.Current.Response.Write(path + "<br>");
                }
                //HttpContext.Current.Response.Write(c + "--" + a + "--" +b + "<br>");

            }
        }

        string IHierarchyData.Type
        {
            get { return _dataIdField; }
        }

        //获取子节点
        IHierarchicalEnumerable IHierarchyData.GetChildren()
        {
            CustomHierarchicalEnumerable children = new CustomHierarchicalEnumerable();

            foreach (DataRow row in _item.Table.Rows)
            {
                string a = row[_dataParentIdField].ToString();
                string b = _item[_dataIdField].ToString();
                if (a == b)
                    children.Add(new CustomHierarchyData(_dataParentIdField, _dataIdField, row));
            }

            return children;
        }

        //获取父节点
        IHierarchyData IHierarchyData.GetParent()
        {
            foreach (DataRow row in _item.Table.Rows)
            {
                string a = _item[_dataParentIdField].ToString();
                string b = row[_dataIdField].ToString();
                if (a == b)
                    return new CustomHierarchyData(_dataParentIdField, _dataIdField, row);
            }

            return null;
        }

        #region ICustomTypeDescriptor Members

        System.ComponentModel.AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        string ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        System.ComponentModel.TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            DataColumnCollection dcs = _item.Table.Columns;

            if (dcs.Count > 0)
            {
                List<CustomHierarchyDataPropertyDescriptor> list = new List<CustomHierarchyDataPropertyDescriptor>();

                foreach (DataColumn dc in dcs)
                {
                    list.Add(new CustomHierarchyDataPropertyDescriptor(dc.ColumnName));
                }

                CustomHierarchyDataPropertyDescriptor[] arr = new CustomHierarchyDataPropertyDescriptor[list.Count];
                list.CopyTo(arr);

                return new PropertyDescriptorCollection(arr);
            }


            return PropertyDescriptorCollection.Empty;

        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return ((ICustomTypeDescriptor)this).GetProperties(null);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            if (pd is CustomHierarchyDataPropertyDescriptor)
            {
                return this;
            }

            return null;
        }

        #endregion
    }

    public class CustomHierarchyDataPropertyDescriptor : PropertyDescriptor
    {
        private string name;


        public CustomHierarchyDataPropertyDescriptor(string name)
            : base(name, null)
        {
            this.name = name;
        }

        public override string Name
        {
            get { return name; }
        }

        public override Type ComponentType
        {
            get
            {
                return typeof(CustomHierarchyData);
            }
        }

        public override bool IsReadOnly
        {
            get
            {
                return true;
            }
        }

        public override Type PropertyType
        {
            get
            {
                return Type.GetType("System.String");
            }
        }


        public override bool CanResetValue(object o)
        {
            return false;
        }

        public override object GetValue(object o)
        {
            CustomHierarchyData shd = o as CustomHierarchyData;

            if (shd != null)
            {
                IHierarchyData hd = (IHierarchyData)shd;
                string subject = ((DataRow)(hd.Item))[name].ToString();
                return subject;
            }

            return null;
        }

        public override void ResetValue(object o)
        {
            throw new NotSupportedException();
        }


        public override void SetValue(object o, object value)
        {
            throw new NotSupportedException();
        }

        public override bool ShouldSerializeValue(object o)
        {
            return true;
        }

        public override System.ComponentModel.TypeConverter Converter
        {
            get { return TypeDescriptor.GetConverter(typeof(System.String)); }
        }
    }

    #endregion

    #region DataTable IList 互相转换

    public static class DataTableExtensions
    {

        /// <summary>
        /// 转化一个DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(this IEnumerable<T> list)
        {

            //创建属性的集合

            List<PropertyInfo> pList = new List<PropertyInfo>();

            //获得反射的入口

            Type type = typeof (T);

            DataTable dt = new DataTable();

            //把所有的public属性加入到集合 并添加DataTable的列

            Array.ForEach<PropertyInfo>(type.GetProperties(), p =>
                {
                    pList.Add(p);
                    dt.Columns.Add(p.Name, p.PropertyType);
                });

            foreach (var item in list)
            {

                //创建一个DataRow实例

                DataRow row = dt.NewRow();

                //给row 赋值

                pList.ForEach(p => row[p.Name] = p.GetValue(item, null));

                //加入到DataTable

                dt.Rows.Add(row);

            }

            return dt;

        }



        /// <summary>
        /// DataTable 转换为List 集合
        /// </summary>
        /// <typeparam name="TResult">类型</typeparam>
        /// <param name="dt">DataTable</param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataTable dt) where T : class, new()
        {

            //创建一个属性的列表

            List<PropertyInfo> prlist = new List<PropertyInfo>();

            //获取TResult的类型实例  反射的入口

            Type t = typeof (T);

            //获得TResult 的所有的Public 属性 并找出TResult属性和DataTable的列名称相同的属性(PropertyInfo) 并加入到属性列表 

            Array.ForEach<PropertyInfo>(t.GetProperties(), p => { if (dt.Columns.IndexOf(p.Name) != -1) prlist.Add(p); });

            //创建返回的集合

            List<T> oblist = new List<T>();



            foreach (DataRow row in dt.Rows)
            {

                //创建TResult的实例

                T ob = new T();

                //找到对应的数据  并赋值

                prlist.ForEach(p => { if (row[p.Name] != DBNull.Value) p.SetValue(ob, row[p.Name], null); });

                //放入到返回的集合中.

                oblist.Add(ob);

            }

            return oblist;

        }





        /// <summary>
        /// 将集合类转换成DataTable
        /// </summary>
        /// <param name="list">集合</param>
        /// <returns></returns>
        public static DataTable ToDataTableTow(IList list)
        {

            DataTable result = new DataTable();

            if (list.Count > 0)
            {

                PropertyInfo[] propertys = list[0].GetType().GetProperties();

                foreach (PropertyInfo pi in propertys)
                {

                    result.Columns.Add(pi.Name, pi.PropertyType);

                }



                for (int i = 0; i < list.Count; i++)
                {

                    ArrayList tempList = new ArrayList();

                    foreach (PropertyInfo pi in propertys)
                    {

                        object obj = pi.GetValue(list[i], null);

                        tempList.Add(obj);

                    }

                    object[] array = tempList.ToArray();

                    result.LoadDataRow(array, true);

                }

            }

            return result;

        }



        /**/

        /// <summary>
        /// 将泛型集合类转换成DataTable
        /// </summary>
        /// <typeparam name="T">集合项类型</typeparam>
        /// <param name="list">集合</param>
        /// <returns>数据集(表)</returns>
        public static DataTable ToDataTable<T>(IList<T> list)
        {

            return ToDataTable<T>(list, null);

        }



        /**/

        /// <summary>
        /// 将泛型集合类转换成DataTable
        /// </summary>
        /// <typeparam name="T">集合项类型</typeparam>
        /// <param name="list">集合</param>
        /// <param name="propertyName">需要返回的列的列名</param>
        /// <returns>数据集(表)</returns>
        public static DataTable ToDataTable<T>(IList<T> list, params string[] propertyName)
        {

            List<string> propertyNameList = new List<string>();

            if (propertyName != null)

                propertyNameList.AddRange(propertyName);



            DataTable result = new DataTable();

            if (list.Count > 0)
            {

                PropertyInfo[] propertys = list[0].GetType().GetProperties();

                foreach (PropertyInfo pi in propertys)
                {

                    if (propertyNameList.Count == 0)
                    {

                        result.Columns.Add(pi.Name, pi.PropertyType);

                    }

                    else
                    {

                        if (propertyNameList.Contains(pi.Name))

                            result.Columns.Add(pi.Name, pi.PropertyType);

                    }

                }



                for (int i = 0; i < list.Count; i++)
                {

                    ArrayList tempList = new ArrayList();

                    foreach (PropertyInfo pi in propertys)
                    {

                        if (propertyNameList.Count == 0)
                        {

                            object obj = pi.GetValue(list[i], null);

                            tempList.Add(obj);

                        }

                        else
                        {

                            if (propertyNameList.Contains(pi.Name))
                            {

                                object obj = pi.GetValue(list[i], null);

                                tempList.Add(obj);

                            }

                        }

                    }

                    object[] array = tempList.ToArray();

                    result.LoadDataRow(array, true);

                }

            }

            return result;

        }

        public static DataTable nullListToDataTable(IList list)
        {
            DataTable result = new DataTable();

            object temp;
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();

                for (int i = 0; i < propertys.Length; i++)
                {
                    Type propType = propertys[i].PropertyType;
                    if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof (Nullable<>))
                    {
                        propType = Nullable.GetUnderlyingType(propType);
                    }
                    result.Columns.Add(propertys[i].Name, propType);
                }

                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        object obj = pi.GetValue(list[i], null);
                        tempList.Add(obj);
                    }
                    object[] array = tempList.ToArray();
                    result.LoadDataRow(array, true);
                }
            }
            return result;
        }
    }

    #endregion

}
